package com.lin.springbootcontendnegotiation.component;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import com.lin.springbootcontendnegotiation.po.User;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * 这是一个消息转换器, 专门用于处理 YAML 格式的消息
 * <p>
 *     注意: 所有的消息转化器都必须 实现 HttpMessageConverter 接口,
 *     或者 继承 AbstractHttpMessageConverter 类
 * </p>
 */
public class YamlHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
    // 创建一个对象映射器, 用于序列化/反序列化 yaml 和 Java对象
    // YAMLGenerator.Feature.WRITE_DOC_START_MARKER 禁用文档标记, 否则会多出---
    private static final ObjectMapper objectMapper = new ObjectMapper(
            new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER));

    // 关键点: 将媒体类型和消息转换器绑定 --- 通过构造器
    public YamlHttpMessageConverter() {
        super(new MediaType("text", "yaml", StandardCharsets.UTF_8));
    }

    // 这个方法是判断当前消息转换器是否支持处理某个类型消息
    @Override
    protected boolean supports(Class clazz) {
        return User.class.isAssignableFrom(clazz);
    }

    // 这个方法用于处理接收到的消息 -- yaml 转换为 java 对象
    @Override
    protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        /* 这里的 inputMessage.getBody() 返回值是一个 inputStream, 它是包含客户端发送的数据的载体(包含请求的所有信息)
         * clazz 是要将输入数据反序列化的目标类类型, 通过 objectMapper.readValue(inputStream, clazz) 方法,
         * 将输入数据反序列化为 clazz 类型的对象, 并返回
         */
        return objectMapper.readValue(inputMessage.getBody(), clazz);
    }

    // 这个方法用于处理要发送的消息 -- java 对象转换为 yaml
    @Override
    protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        /* 这里的 outputMessage.getBody() 返回值是一个 outputStream, 它就是发送给客户端的数据的载体
         * o 就是 要发送给客户端的数据, 通过 objectMapper.writeValue(outputStream, o) 方法,
         * 将 o 转换为 yaml 格式的数据, 并且写入到 outputStream 中
         */
        objectMapper.writeValue(outputMessage.getBody(), o);
    }
}
